#include "server_works.h"

static Status serveQuit(int client_fd, int epoll_fd);
static Status serveLogin(int client_fd, sqlite3* db);
static Status serveRegist(int client_fd, sqlite3* db);
static Status serveAddStaff(int client_fd, sqlite3* db);
static Status serveDelStaff(int client_fd, sqlite3* db);
static Status serveUpdateInfo(int client_fd, sqlite3* db);
static Status serveSearch(int client_fd, sqlite3* db);
static Status serveHistory(int client_fd, sqlite3* db);
static Status serveCleanHistory(int client_fd, sqlite3* db);

static Status addHistory(HistoryMsg* msg, sqlite3* db);

/* communicate with client */
/* attention: when this function return Failure, server stopped! */
Status doService(int client_fd, int epoll_fd, sqlite3* db) {
	Status control;
	if (recvStatus(client_fd, &control) == Failure) {
		return Failure;
	}
	
	switch (control) 
	{
		case Quit:
			if (serveQuit(client_fd, epoll_fd) == Failure) {
				return Failure;
			}
			return Success;
			break;
		case Login:
			if (serveLogin(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		case Regist:
			if (serveRegist(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		case AddStaff:
			if (serveAddStaff(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		case DelStaff:
			if (serveDelStaff(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		case UpdateInfo:
			if (serveUpdateInfo(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		case SearchInfo:
			if (serveSearch(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		case History:
			if (serveHistory(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		case CleanHistory:
			if (serveCleanHistory(client_fd, db) == Failure) {
				return Failure;
			}
			break;
		default:
			UNEXCEPT_BRANCH;
			return Failure;
			break;
	}
	return Success;
}

static Status serveQuit(int client_fd, int epoll_fd) {
	/* remove client_fd */
	if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL) == -1) {
		PRINT_ERR("epoll del");
		return Failure;
	}

	/* close client_fd */
	close(client_fd);
	printf("client [%d], offline\n", client_fd);
	return Success;
}

static Status serveLogin(int client_fd, sqlite3* db) {
	Status control;
	LoginMsg msg;
	char** result = NULL;
	int row, col;
	/* recv LoginMsg*/
	if (recvLogin(client_fd, &msg) == Failure) {
		return Failure;
	}
	// search
	if (dataSearchInfo(db, &msg, NULL, NULL, &result, &row, &col) == Failure) {
		control = Stop;
		if (sendStatus(client_fd, &control) == Failure) {
			return Failure;
		}
		return Success;
	} else {
		control = Continue;
	}
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}
	if(sendLogin(client_fd, &msg) == Failure) {
		return Failure;
	}
    HistoryMsg h_msg;
	h_msg.ID = msg.ID;
	sprintf(h_msg.action, "LOGIN  ");
	addHistory(&h_msg, db);
	return Success;
}

static Status serveRegist(int client_fd, sqlite3* db) {
	Status control;
	LoginMsg l_msg;
	StaffMsg s_msg;
	/* recv LoginMsg*/
	if (recvLogin(client_fd, &l_msg) == Failure) {
		return Failure;
	}
	if (recvStaff(client_fd, &s_msg) == Failure) {
		return Failure;
	}	
	// search
	if (dataInsert(db, &l_msg, &s_msg, NULL) == Failure) {
		control = Stop;	
	} else {
		control = Continue;
	}
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}
	return Success;
}

static Status serveAddStaff(int client_fd, sqlite3* db) {
	Status control;
	StaffMsg msg;
	if (recvStaff(client_fd, &msg) == Failure) {
		return Failure;
	}
	// insert
	if (dataInsert(db, NULL, &msg, NULL) == Failure) {
		control = Stop;
	} else {
		control = Continue;
	}
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}
    HistoryMsg h_msg;
	h_msg.ID = msg.ID;
	sprintf(h_msg.action, "ADDUSR ");
	addHistory(&h_msg, db);
	return Success;
}

static Status serveDelStaff(int client_fd, sqlite3* db) {
	Status control;
	StaffMsg msg;
	if (recvStaff(client_fd, &msg) == Failure) {
		return Failure;
	}
	// delete
	if (dataDelete(db, NULL, &msg, NULL) == Failure) {
		control = Stop;
	} else {
		control = Continue;
	}
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}
    HistoryMsg h_msg;
	h_msg.ID = msg.ID;
	sprintf(h_msg.action, "DELUSR ");
	addHistory(&h_msg, db);
	return Success;
}

static Status serveUpdateInfo(int client_fd, sqlite3* db) {
	Status control;
	StaffMsg msg;
	if (recvStaff(client_fd, &msg) == Failure) {
		return Failure;
	}
	// update
	if (dataUpdateInfo(db, NULL, &msg, NULL) == Failure) {
		control = Stop;
	} else {
		control = Continue;
	}
	
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}
    HistoryMsg h_msg;
	h_msg.ID = msg.ID;
	sprintf(h_msg.action, "UPDATE ");
	addHistory(&h_msg, db);
	return Success;
}

static Status serveSearch(int client_fd, sqlite3* db) {
	Status control;
	StaffMsg msg;
	char** result = NULL;
	int row, col, i;
	if (recvStaff(client_fd, &msg) == Failure) {
		return Failure;
	}

	/* search*/
	if (dataSearchInfo(db, NULL, &msg, NULL, &result, &row, &col) == Failure) {
		control = Stop;
		if (sendStatus(client_fd, &control) == Failure) {
			return Failure;
		}
		return Success;
	} else {
		control = Continue;
	}
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}
	msg.flag = 1;
	for (i = 0; i < col; ++i) {
		sprintf(msg.name, "%s", result[i]);
		if (sendStaff(client_fd, &msg) == Failure) {
			return Failure;
		}
	}
	msg.flag = -1;
	if (sendStaff(client_fd, &msg) == Failure) {
		return Failure;
	}
	msg.flag = 1;
	for (i = 1; i <= row; ++i) {
		msg.ID.u_id = atoi(result[i * col]);
		sprintf(msg.name, "%s", result[i*col + 1]);
		msg.age = atoi(result[i * col + 2]);
		msg.tel = atoi(result[i * col + 3]);
		if (sendStaff(client_fd, &msg) == Failure) {
			return Failure;
		}
	}
	msg.flag = -1;
	if (sendStaff(client_fd, &msg) == Failure) {
		return Failure;
	}
	sqlite3_free_table(result);

    HistoryMsg h_msg;
	h_msg.ID = msg.ID;
	sprintf(h_msg.action, "SEARCH ");
	addHistory(&h_msg, db);
	return Success;
}

static Status serveHistory(int client_fd, sqlite3* db) {
	Status control;
	HistoryMsg msg, temp;
	char** result = NULL;
	int row, col, i;
	if (recvHistory(client_fd, &msg) == Failure) {
		return Failure;
	}
	/* search*/
	if (dataSearchInfo(db, NULL, NULL, &msg, &result, &row, &col) == Failure) {
		control = Stop;
		if (sendStatus(client_fd, &control) == Failure) {
			return Failure;
		}
		return Success;
	} else {
		control = Continue;
	}
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}
	temp.flag = 1;
	for (i = 1; i <= row; ++i) {
		temp.ID.a_id = atoi(result[i * col]);
		sprintf(temp.action, "%s", result[i*col + 1]);
		sprintf(temp.my_time, "%s", result[i*col + 2]);
		if (sendHistory(client_fd, &temp) == Failure) {
			return Failure;
		}
	}
	temp.flag = -1;
	if (sendHistory(client_fd, &temp) == Failure) {
		return Failure;
	}
	sqlite3_free_table(result);

	sprintf(msg.action, "HISTORY");
	addHistory(&msg, db);
	return Success;
}

static Status serveCleanHistory(int client_fd, sqlite3* db) {
	Status control;
	HistoryMsg msg;
	if (recvHistory(client_fd, &msg) == Failure) {
		return Failure;
	}
	/* delete */
	if (dataDelete(db, NULL, NULL, &msg) == Failure) {
		control = Stop;
	} else {
		control = Continue;
	}
	if (sendStatus(client_fd, &control) == Failure) {
		return Failure;
	}

	return Success;
}

static Status addHistory(HistoryMsg* msg, sqlite3* db) {
	time_t t;
	time(&t);
	char* p = ctime(&t);
	sprintf(msg->my_time, "%s", p);
	msg->my_time[strlen(msg->my_time) - 1] = '\0';
	dataInsert(db, NULL, NULL, msg);
	return Success;
}
